#ifndef __TOYM__NET__TCP_CONNECTION_H__
#define __TOYM__NET__TCP_CONNECTION_H__

#include "net/Callables.h"
#include "net/InetAddress.h"
#include "net/Channel.h"
#include "net/Socket.h"
#include "Base/noncopyable.h"
#include "Base/Buffer.h"
#include <memory>
#include <string>

namespace toym
{
namespace net
{

class EventLoop;

class TcpConnection: public std::enable_shared_from_this<TcpConnection>, noncopyable {
public:
    TcpConnection(int fd, EventLoop* loop, const InetAddress& localAddr, const InetAddress& peerAddr);
    TcpConnection(Socket sock, EventLoop* loop, const InetAddress& localAddr, const InetAddress& peerAddr);

    ~TcpConnection();

    void setConnName(std::string&& name) {
        m_connName = std::move(name);
    }
    void setConnName(const std::string& name) {
        m_connName = name;
    }
    std::string& getConnName() {
        return m_connName;
    }
    const std::string& getConnName() const {
        return m_connName;
    }

    const InetAddress& getPeerAddr() const {
        return m_peerAddr;
    }

    const InetAddress& getLocalAddr() const {
        return m_localAddr;
    }

    void setConnectionCb(const ConnectionCallback_t& cb) {
        m_connectionCb = cb;
    }
    void setConnectionCb(ConnectionCallback_t&&cb) {
        m_connectionCb = std::move(cb);
    }

    void setMessageCb(const MessageCallback_t& cb) {
        m_messageCb = cb;
    }
    void setMessageCb(MessageCallback_t&& cb) {
        m_messageCb = std::move(cb);
    }

    void setCloseCb(const CloseCallback_t& cb) {
        m_closeCb = cb;
    }
    void setCloseCb(CloseCallback_t&& cb) {
        m_closeCb = std::move(cb);
    }

    void setWriteComplateCb(const WriteComplateCallback_t cb) {
        m_writeComplateCb = cb;
    }
    void setWriteComplateCb(WriteComplateCallback_t&& cb) {
        m_writeComplateCb = std::move(m_writeComplateCb);
    }

    EventLoop* getLoop() {
        return m_loop;
    }

    void connectionEstablished();

    bool connected() {
        return m_state == State::eConnected;
    }

    // 线程安全的send
    void send(const std::string& msg);

    // 线程安全
    void shutdown();

    void connectionDestroy();

private:

    enum class State { eConnecting, eConnected, eDisconnecting, eDisconnected };

    void handleClose();
    void handleError();

    void handleRead();
    void handleWrite();

    void sendInLoop(const std::string& msg);

    void shutdownInLoop();


    void setState(State state) {
        m_state = state;
    }

    int m_fd;
    Socket m_sock;
    EventLoop* m_loop;
    InetAddress m_localAddr;
    InetAddress m_peerAddr;
    Channel m_channel;
    ConnectionCallback_t m_connectionCb;
    MessageCallback_t m_messageCb;
    CloseCallback_t m_closeCb;
    WriteComplateCallback_t m_writeComplateCb;
    HighWaterMarkCallback_t m_highWaterMarkCb; // unused
    Buffer m_readBuf;
    Buffer m_writeBuf;
    State m_state;
    std::string m_connName;
};

} // namespace net

} // namespace toym


#endif //__TOYM__NET__TCP_CONNECTION_H__